# coding=utf-8
"""
@author : leecrest
@time   : 2014/8/16 21:37
@brief  : 万物之源
"""

from wafer.modules import configcenter, datacache
from wafer import log
from wafer import timer
import time


########################################################################################################################
def GetSecond():
	return time.time()

#单属性类
class CVariable:
	def __init__(self, iID, sName, sValue, iValidTime, bUseOnline=False):
		self.m_ID = iID
		self.m_Name = sName
		self.m_Value = sValue
		self.m_ValidTime = iValidTime
		self.m_UseOnline = bUseOnline
		if iValidTime > 0:
			self.m_StartTime = GetSecond()


	def IsValid(self):
		if self.m_ValidTime <= 0:
			return True
		return self.m_StartTime + self.m_ValidTime < GetSecond()


	def GetValue(self):
		if not self.IsValid():
			return False, None
		return True, self.m_Value


	def SetValue(self, sValue, sReason):
		log.LogFile("CacheCell", "Set_%s, %s->%s, %s", self.m_Name, self.m_Value, sValue, sReason)
		self.m_Value = sValue


	def Load(self, data):
		self.m_ValidTime = data.get("ValidTime", 0)
		self.m_StartTime = data.get("StartTime", 0)
		if self.m_UseOnline:
			self.m_StartTime += GetSecond() - data["SaveTime"]
		self.m_Value = data["Value"]


	def Save(self):
		data = {"Name":self.m_Name, "Value":self.m_Value}
		if self.m_ValidTime:
			iCurTime = GetSecond()
			iLeftTime = self.m_StartTime + self.m_ValidTime - iCurTime
			if iLeftTime <= 0:
				return
			data["StartTime"] = self.m_StartTime
			data["ValidTime"] = self.m_ValidTime
			if self.m_UseOnline:
				data["SaveTime"] = iCurTime
		return data


class CVarMgr(datacache.CCache):
	"""
	缓存管理器
	所有缓存属性划分为2类：
	1、临时属性：在玩家生命周期中存在，也可指定有效时长。
		临时属性不需要ID，由属性名称为key即可
	2、存盘属性：在玩家生命周期中存在，在属性值变化时存盘。
		存盘属性的ID可从配置中读取，也可以由系统生成，从1开始递增
	"""

	def __init__(self, iOwnerID, sTable, sDefName=None):
		super(CVarMgr, self).__init__(sTable, iOwnerID)
		self.m_ID = iOwnerID
		self.m_TempVarDict = {}
		self.m_SaveVarDict = {}
		self.m_SaveName2ID = {}
		self.m_SaveAllocID = 0
		self.m_SyncDict = {}
		self.m_Table = sTable
		self.m_DefName = sDefName
		if self.m_DefName:
			self.InitByDef()

	def __del__(self):
		if self.m_Table:
			datacache.UnRegCache(self.m_Table, self.m_ID)

	def Load(self):
		if not self.m_Table:
			return
		datacache.RegCache(self.m_Table, self.m_ID, self)


	def InitByDef(self):
		dConfig = configcenter.GetConfig(self.m_DefName)
		if not dConfig:
			return
		#临时属性
		sVarDict = dConfig.get("Temp", {})
		for sName, sVarInfo in sVarDict.iteritems():
			self.m_TempVarDict[sName] = CVariable(
				0, sName, sVarInfo.get("Value", None),
				sVarInfo.get("Time", 0), sVarInfo.get("UseOnline", False)
			)
			self.m_SyncDict[sName] = sVarInfo.get("Sync", False)

		#存盘属性
		sVarDict = dConfig.get("Save", [])
		for sName, sVarInfo in sVarDict.iteritems():
			iVarID = sVarInfo.get("ID", None)
			if not iVarID:
				continue
			self.m_SaveName2ID[sName] = iVarID
			self.m_SaveVarDict[iVarID] = CVariable(
				iVarID, sName, sVarInfo.get("Value", None),
				sVarInfo.get("Time", 0), sVarInfo.get("UseOnline", False)
			)
			if iVarID > self.m_SaveAllocID:
				self.m_SaveAllocID = iVarID + 1
			self.m_SyncDict[sName] = sVarInfo.get("Sync", False)


	def OnLoad(self, data):
		if not data:
			return
		for sName, dInfo in data.iteritems():
			iVarID = self.m_SaveName2ID.get(sName, None)
			if not iVarID:
				continue
			obj = self.m_SaveVarDict[iVarID]
			obj.Load(dInfo)


	def OnSave(self):
		data = {}
		for sName, iVarID in self.m_SaveName2ID.iteritems():
			obj = self.m_SaveVarDict[iVarID]
			if not obj:
				continue
			dSave = obj.Save()
			if dSave:
				data[sName] = dSave
		return data


	def RegTempVar(self, sName, sValue=None, iValidTime=0, bUseOnline=False):
		"""
		注册临时属性，在对象的生命周期中都有效
		:param sName: string，属性名称
		:param sValue: 默认值
		:param iValidTime：有效时间，0或者负数表示无限制，单位：秒
		:param bUseOnline：是否采用在线计时
		:return: True/False：操作是否成功
		"""
		if not sName:
			return False
		if sName in self.m_TempVarDict:
			log.Fatal(u"临时属性 %s 已经注册，请检查", sName)
			return False
		self.m_TempVarDict[sName] = CVariable(0, sName, sValue, iValidTime, bUseOnline)
		return True


	def RegSaveVar(self, sName, sValue=None, iValidTime=0, bUseOnline=False):
		"""
		注册存盘属性。当属性变化时，会存入数据库中
		:param sName: string，属性名称
		:param sValue: 默认值
		:param iValidTime：有效时间，0或者负数表示无限制，单位：秒
		:param bUseOnline：是否采用在线计时
		:return: True/False：操作是否成功
		"""
		if not sName:
			return False
		if sName in self.m_SaveName2ID:
			log.Fatal(u"存盘属性 %s 已经注册，请检查", sName)
			return False
		if self.m_SaveAllocID >= 255:
			log.Fatal(u"存盘属性编号不足，需要扩充")
			return False
		iVarID = self.m_SaveAllocID
		self.m_SaveAllocID += 1
		self.m_SaveName2ID[sName] = iVarID
		self.m_SaveVarDict[iVarID] = CVariable(iVarID, sName, sValue, iValidTime, bUseOnline)
		self.Update()
		return True


	def GetValue(self, sName, default=None):
		"""
		查询指定名称的属性值，当属性不存在时，返回default
		:param sName: 属性名称
		:param default: 默认值
		:return:
		"""
		obj = self.m_TempVarDict.get(sName, None)
		if obj:
			Ret, sValue = obj.GetValue()
			if Ret:
				return sValue
			else:
				del self.m_TempVarDict[sName]
				return default
		iVarID = self.m_SaveName2ID.get(sName, None)
		if iVarID:
			Ret, sValue = self.m_SaveVarDict[iVarID].GetValue()
			if Ret:
				return sValue
			else:
				del self.m_SaveName2ID[sName]
				del self.m_SaveVarDict[iVarID]
				return default
		return default


	def SetValue(self, sName, sValue, sReason):
		obj = self.GetVarObj(sName)
		if not obj or obj.m_Value == sValue:
			return
		obj.SetValue(sValue, sReason)
		self.Update()
		return True


	def AddValue(self, sName, sValue, sReason):
		obj = self.GetVarObj(sName)
		if not obj:
			return
		iNewValue = obj.GetValue() + sValue
		obj.SetValue(iNewValue, sReason)
		self.Update()
		return True


	def GetVarObj(self, sName):
		obj = self.m_TempVarDict.get(sName, None)
		if not obj:
			iVarID = self.m_SaveName2ID.get(sName, None)
			if not iVarID:
				return
			obj = self.m_SaveVarDict[iVarID]
		if not obj or not obj.IsValid():
			return
		return obj


	def GetVarInfo(self, sName):
		obj = self.GetVarObj(sName)
		if not obj:
			return
		data = {
			"ID" : obj.m_ID,
			"Name" : sName,
		    "Value" : obj.GetValue(),
		}
		return data


	def IsSync(self, sProp):
		return sProp in self.m_SyncDict


########################################################################################################################
#万物基类
class CBaseObj(CVarMgr):
	TABLE = None
	DEFINE = None

	def __init__(self, ID):
		super(CBaseObj, self).__init__(ID, self.TABLE, self.DEFINE)
		self.m_ID  = ID
		self.__InitEvent()


	def __InitEvent(self):
		self.m_EventDict = {}
		self.m_EventLock = False
		self.m_EventAllocID = 0


	def AddEvent(self, sName, cbFunc, iCount=0, Time=0):
		if not sName in self.m_EventDict:
			self.m_EventDict[sName] = {}
		dEvents = self.m_EventDict[sName]
		for dInfo in dEvents.iteritems():
			if dInfo["Func"] == cbFunc:
				log.Fatal(u"%d 事件 %s 重复订阅", (self.m_ID, sName, cbFunc))
				return
		if self.m_EventLock == sName:
			log.Fatal(u"%d 订阅事件 %s 失败，当前正在事件处理中，无法订阅", (self.m_ID, sName, cbFunc))
			return
		self.m_EventAllocID += 1
		iEventID = self.m_EventAllocID
		dInfo = {"Func":cbFunc, "MaxCount":iCount, "Time":Time}
		if Time > 0:
			dInfo["Start"] = time.time()
		if iCount > 0:
			dInfo["CurCount"] = iCount
		dEvents[iEventID] = dInfo
		return iEventID


	def DelEvent(self, sName, iEventID):
		if not sName or not iEventID:
			return
		dEvents = self.m_EventDict.get(sName, None)
		if not dEvents or not iEventID in dEvents:
			return
		if self.m_EventLock == sName:
			log.Fatal(u"%d 取消事件 %s 失败，当前正在事件处理中，无法取消", (self.m_ID, sName, dEvents[iEventID]["Func"]))
			return
		del dEvents[iEventID]
		if not dEvents:
			del self.m_EventDict[sName]
		return True


	def OnEvent(self, sName, dEventData={}):
		dEvents = self.m_EventDict.get(sName, None)
		if not dEvents:
			return
		self.m_EventLock = sName
		iDelList = []
		iCurTime = time.time()
		for iEventID, dInfo in dEvents.iteritems():
			if dInfo.get("CurCount", 0) < 0:
				iDelList.append(iEventID)
				continue
			if dInfo["Time"] > 0 and dInfo["Start"] + dInfo["Time"] < iCurTime:
				iDelList.append(iEventID)
				continue
			dInfo["Func"](dEventData)
			if dInfo["MaxCount"] > 0:
				dInfo["CurCount"] -= 1
				if dInfo["CurCount"] <= 0:
					iDelList.append(iEventID)
		for iEventID in iDelList:
			if iEventID in dEvents:
				del dEvents
		if not dEvents:
			del self.m_EventDict[sName]
		self.m_EventLock = None


	def AddTimer(self, sName, cbFunc, iDelay=0, iInterval=0, iCount=0):
		if not sName or not cbFunc:
			return
		timer.SetTimer(self.m_ID, sName, cbFunc, iDelay, iInterval, iCount)

	def DelTimer(self, sName=None):
		if not sName:
			timer.RemoveTimer(self.m_ID)
		else:
			timer.RemoveTimer(self.m_ID, sName)
